#pragma once

#include <stdbool.h>

#include "share/std_err.h"

// SCPI 指令字段最大长度
#define SCPI_CMD_PART_SIZE	20
// SCPI 指令字段最大数量
#define SCPI_CMD_PART_COUNT	20
// SCPI 指令单个参数最大长度
#define SCPI_CMD_ARG_SIZE	128
// SCPI 指令参数最大数量
#define SCPI_CMD_ARG_COUNT	2000
// SCPI 指令组中最大指令数量
#define SCPI_CMD_GROUP_SIZE	20

// SCPI 命令字段（子命令）
typedef struct _scpi_cmd_part {
	// 命令后面带的数值（>= 0 时有效）
	//int var;
	// 命令字符串
	char str[SCPI_CMD_PART_SIZE];
} scpi_cmd_part_t;

// SCPI 命令参数
typedef struct _scpi_cmd_arg {
	// 是否是带引号的字符串参数
	bool is_string;
	// 参数字符串
	char str[SCPI_CMD_ARG_SIZE];
} scpi_cmd_arg_t;

// SCPI 命令
typedef struct _scpi_cmd {
	// 是否是 '*' 开头的通用命令
	bool is_asterisk;
	// 是否是 '?' 结尾的查询命令
	bool is_query;
	// 命令字段数组（子命令）有效长度
	int part_count;
	// 参数数组有效长度
	int arg_count;
	// 命令字段数组（子命令）
	scpi_cmd_part_t parts[SCPI_CMD_PART_COUNT];
	// 参数数组
	scpi_cmd_arg_t args[SCPI_CMD_ARG_COUNT];
} scpi_cmd_t;

// SCPI 命令组
typedef struct _scpi_cmd_group {
	// SCPI 命令有效个数
	int cmd_count;
	// SCPI 命令数组
	scpi_cmd_t cmds[SCPI_CMD_GROUP_SIZE];
} scpi_cmd_group_t;


#ifdef __cplusplus
extern "C" {
#endif

/**
 * 准备解析使用的资源
 * @param data [in] SCPI 指令字符串（可以不以 '\0' 结束），长度为 datalen。
 * @param datalen SCPI 指令字符串长度。
 * @param pyybuf [out] SCPI 解析缓冲区。解析完成后应调用 scpi_parse_finish() 释放资源。
 * @return 标准错误码。
 */
std_err_t scpi_parse_prepare(const char* data, size_t datalen, void** pyybuf);

/**
 * 启动解析
 * @param pcmds [out] SCPI 指令解析结果指针。在调用 scpi_parse_finish() 前有效。如果 *pcmds 为 NULL，表示没有解析出 SCPI 指令。
 * @return 标准错误码。
 */
std_err_t scpi_parse_next(scpi_cmd_group_t** pcmds);

/**
 * 解析结束，释放资源（包括解析的结果）
 * @param yybuf scpi_parse_prepare() 返回的缓冲区
 * @return 标准错误码
 */
void scpi_parse_finish(void* yybuf);

/**
 * 解析后得到的 SCPI 命令组会调用此回调函数进行处理。
 * @param group 解析后得到的 SCPI 命令组
 * @return 如果此回调函数返回错误，则会中止后面的解析。
 */
typedef std_err_t (*scpi_cmd_group_handler_t)(scpi_cmd_group_t* group, void *cookie);

/**
 * 分组解析 SCPI 脚本
 * @param data [in] SCPI 指令字符串（可以不以 '\0' 结束），长度为 datalen。
 * @param datalen SCPI 指令字符串长度。
 * @param callback 解析后得到的 SCPI 命令组会调用此回调函数进行处理。如果此回调函数返回错误，则会中止后面的解析。
 * @param cookie [in] callback 回调时的参数
 * @return 标准错误码
 */
std_err_t scpi_parse(const char* data, size_t datalen, scpi_cmd_group_handler_t callback, void *cookie);

// 获取 scpi_parse() 过程中产生的最近一次错误
const char* scpi_get_last_error();

// 打印输出 SCPI 命令组中的命令
void scpi_dump_cmd_group(const scpi_cmd_group_t* group);

#ifdef __cplusplus
} //extern "C"
#endif
